/*
 * Copyright 2007 - The JDPF Project Team (http://www.jdpf.org) 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
package org.jdpf.plugins.rgbimage.transformer.histogram.tohistogramtransformer;

import java.util.ArrayList;
import java.util.List;

import org.jdpf.core.kernel.elements.Token;
import org.jdpf.core.plugins.blocks.AbstractTransformerPlugin;
import org.jdpf.core.plugins.datatypes.AbstractDataType;
import org.jdpf.plugins.datatypes.media.Histogram;
import org.jdpf.plugins.datatypes.media.RGBImage;

/**
 * @author Bruno Farina
 * 
 */
public class Image2HistogramTransformer extends AbstractTransformerPlugin {

	private static final int MASK = 0xFF;
	private static final int LEVELS_NUMBER = 256;

	private String _histogramType="full";

	public Image2HistogramTransformer(String transitionId, String transitionName) {
		super(transitionId, transitionName);
	}

	@Override
	public Token process(List<Token> list) {
		List<AbstractDataType> inList = list.get(0).getValueList();
		List<AbstractDataType> outList=new ArrayList<AbstractDataType>(5);
		double tot=0.0;
//		Total size calculation loop
		for(AbstractDataType data:inList){
			RGBImage img=(RGBImage) data;
			tot+=img.getH()*img.getW();
		}
		
		for (int i = 0; i < inList.size(); i++) {
			RGBImage image = (RGBImage) inList.get(i);
			List<int[]> channels = separateColorChannels(image);
			double[] rch = extractHistogram(channels.get(0));
			double[] gch = extractHistogram(channels.get(1));
			double[] bch = extractHistogram(channels.get(2));
			
			if(_histogramType.equalsIgnoreCase("normalized")){
				rch=normalizeHistogram(rch,image.getH()*image.getW());
				gch=normalizeHistogram(gch,image.getH()*image.getW());
				bch=normalizeHistogram(bch,image.getH()*image.getW());
			}
			
			Histogram hist = new Histogram(rch, gch, bch, image.getFileName());
			outList.add(i,hist);
			percentage=Math.min(100.0,percentage+image.getH()*image.getW()/tot*100);
			this.log(this,this.getPluginId(),this.getId(),"Histogram successfully calculated for image "+
					image.getFileName()+".");
		}
		Token outToken=new Token();
		outToken.setValueList(outList);
		return outToken;
	}
	
	/**Method to separete the R-G-B channel of a given image.
	 * @param image - RGBImage input image
	 * @return R-G-B separated channels
	 */
	private List<int[]> separateColorChannels(RGBImage image) {
		List<int[]> outList = new ArrayList<int[]>(3);
		int[] data = (int[]) image.getValue();
		int[] rch = new int[data.length];
		int[] gch = new int[data.length];
		int[] bch = new int[data.length];
		for (int i = 0; i < data.length && start; i++) {
			rch[i] = (data[i] >> 16) & MASK;
			gch[i] = (data[i] >> 8) & MASK;
			bch[i] = data[i] & MASK;
		}
		outList.add(0, rch);
		outList.add(1, gch);
		outList.add(2, bch);
		return outList;
	}
	
	/**Method to calculate an histogram from a channel (R-G-B) of a given image.
	 * @param imagePixels - an image channel pixels
	 * @return an array representing the histogram for the given image channel
	 */
	private double[] extractHistogram(int[] imagePixels){
		double[] histogram=new double[LEVELS_NUMBER];
		for (int j = 0; j < imagePixels.length&&start; j++) {
			histogram[imagePixels[j]]++;
		}
		return histogram;
	}

	/**Method to normalize an histogram
	 * @param inputHistogram - the histogram of an image
	 * @param totalPixels - the total number of pixel of the image
	 * @return the normalized histogram
	 */
	private double[] normalizeHistogram(double[] inputHistogram, int totalPixels) {
		double[] normalized=new double[inputHistogram.length];
		for(int i=0;i<inputHistogram.length&&start;i++){
			normalized[i]=inputHistogram[i]/totalPixels;
		}
		return normalized;
	}

	public void setHistogramType(String type) {
		_histogramType = type;
	}

}
